<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';

import {
  DrawerPosition,
  DrawerSize,
  DrawerType,
} from '@fluentui/web-components';

/**
 * Props for the Drawer component
 */
interface DrawerProps {
  /**
   * The ID of the element that describes the drawer
   */
  ariaDescribedby?: string;

  /**
   * The ID of the element that labels the drawer
   */
  ariaLabelledby?: string;

  /**
   * Determines whether the drawer should be displayed as modal, non-modal, or alert
   * - modal: Blocks interaction with the page until dismissed
   * - non-modal: Allows interaction with the page while open
   * - inline: Inline drawer without overlay
   */
  type?: 'alert' | 'inline' | 'modal' | 'non-modal';

  /**
   * Sets the position of the drawer (start/end)
   */
  position?: 'end' | 'start';

  /**
   * Sets the size of the drawer (small/medium/large)
   */
  size?: 'large' | 'medium' | 'small';

  /**
   * Controls the visibility of the drawer (v-model binding)
   */
  modelValue?: boolean;
}

const props = withDefaults(defineProps<DrawerProps>(), {
  ariaDescribedby: undefined,
  ariaLabelledby: undefined,
  type: DrawerType.modal,
  position: DrawerPosition.start,
  size: DrawerSize.medium,
  modelValue: false,
});

/**
 * Emitted events
 */
const emit = defineEmits<{
  /**
   * Emitted before the drawer's open state changes
   */
  beforetoggle: [event: CustomEvent];

  /**
   * Emitted after the drawer's open state changes
   */
  toggle: [event: CustomEvent];

  /**
   * Update the model value (for v-model binding)
   */
  'update:modelValue': [value: boolean];
}>();

// Reference to the drawer element
const drawerRef = ref<HTMLElement | null>(null);

// Track internal drawer state
const isOpen = ref(false);

/**
 * Show the drawer
 */
const show = () => {
  if (drawerRef.value) {
    (drawerRef.value as any).show();
    emit('update:modelValue', true);
  }
};

/**
 * Hide the drawer
 */
const hide = () => {
  if (drawerRef.value) {
    (drawerRef.value as any).hide();
    emit('update:modelValue', false);
  }
};

/**
 * Handle clicking on the drawer backdrop for light-dismiss
 */
const clickHandler = (event: Event) => {
  if (
    drawerRef.value &&
    event.target === drawerRef.value &&
    props.type === DrawerType.modal
  ) {
    hide();
  }
};

// Watch for modelValue changes from parent
watch(
  () => props.modelValue,
  (newValue) => {
    if (newValue && !isOpen.value) {
      show();
    } else if (!newValue && isOpen.value) {
      hide();
    }
  },
  { immediate: true },
);

// Handle toggle events to keep local state in sync
onMounted(() => {
  if (drawerRef.value) {
    drawerRef.value.addEventListener('toggle', (e: Event) => {
      const customEvent = e as CustomEvent;
      isOpen.value = customEvent.detail.newState === 'open';
      emit('update:modelValue', isOpen.value);
      emit('toggle', customEvent);
    });

    drawerRef.value.addEventListener('beforetoggle', (e: Event) => {
      const customEvent = e as CustomEvent;
      emit('beforetoggle', customEvent);
    });

    // Set initial state
    if (props.modelValue) {
      show();
    }
  }
});

// Expose methods to parent
defineExpose({
  show,
  hide,
  drawer: drawerRef,
});
</script>

<template>
  <fluent-drawer
    :aria-describedby="ariaDescribedby"
    :aria-labelledby="ariaLabelledby"
    :type="type"
    :position="position"
    :size="size"
    ref="drawerRef"
    @click="clickHandler"
  >
    <slot></slot>
  </fluent-drawer>
</template>
